package com.tencent.sr.iris.activity.service.activity.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import com.tencent.sr.iris.activity.common.config.DependencyConfig;
import com.tencent.sr.iris.activity.common.config.IrisThreadPoolConfig;
import com.tencent.sr.iris.activity.common.enums.*;
import com.tencent.sr.iris.activity.common.util.*;
import com.tencent.sr.iris.activity.dependency.qufa.GroupTaskDependency;
import com.tencent.sr.iris.activity.dependency.user.UserCoreDependency;
import com.tencent.sr.iris.activity.domain.event.dto.EsQueryDTO;
import com.tencent.sr.iris.activity.domain.event.dto.InviteLimitDTO;
import com.tencent.sr.iris.activity.interfaces.dto.ActivityComponentTextDTO;
import com.tencent.sr.iris.activity.interfaces.dto.AwardInfoDTO;
import com.tencent.sr.iris.activity.interfaces.dto.MultiTaskActivityDTO;
import com.tencent.sr.iris.activity.interfaces.dto.TargetThresholdVO;
import com.tencent.sr.iris.activity.interfaces.enums.*;
import com.tencent.sr.iris.activity.interfaces.request.acticity.*;
import com.tencent.sr.iris.activity.interfaces.request.task.EventRetryRequest;
import com.tencent.sr.iris.activity.interfaces.request.task.PersonalPerformanceReq;
import com.tencent.sr.iris.activity.interfaces.response.activity.*;
import com.tencent.sr.iris.activity.interfaces.response.group.task.QuFaPerformancePersonalRes;
import com.tencent.sr.iris.activity.interfaces.response.group.task.TaskCommissionDetailResponse;
import com.tencent.sr.iris.activity.repository.Criteria;
import com.tencent.sr.iris.activity.repository.entity.*;
import com.tencent.sr.iris.activity.repository.mapper.TIrisActivityAwardRecordMapper;
import com.tencent.sr.iris.activity.repository.mapper.TIrisUserTaskRecordMapper;
import com.tencent.sr.iris.activity.repository.mapper.example.TIrisUserTaskRecordExample;
import com.tencent.sr.iris.activity.service.activity.*;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.constant.ActivityConfigConstants;
import com.tencent.sr.iris.activity.service.convert.AwardStaticConvert;
import com.tencent.sr.iris.activity.service.convert.UserTaskRecordConvert;
import com.tencent.sr.iris.activity.service.event.job.ActivityTaskEventRetryJob;
import com.tencent.sr.iris.activity.service.event.util.ActivityCommonUtilService;
import com.tencent.sr.iris.activity.service.event.vo.InviteActivityInfoVO;
import com.tencent.sr.iris.activity.service.event.vo.MonthActivityInfoVO;
import com.tencent.sr.iris.activity.service.util.ESUtils;
import com.tencent.sr.iris.activity.service.util.IdCreateorUtil;
import com.tencent.sr.iris.user.core.service.interfaces.response.activity.SupervisorRelationResponse;
import com.tencent.sr.rmall.common.exception.retail.TRetailBizException;
import com.tencent.sr.rmall.common.exception.retail.TRetailErrorException;
import com.tencent.sr.rmall.common.primitive.HttpResult;
import com.tencent.sr.rmall.common.request.PaginationRequest;
import com.tencent.sr.rmall.common.response.PaginationResponse;
import com.tencent.sr.rmall.material.interfaces.enums.EYesNo;
import com.tencent.sr.rmall.springbootstarter.redis.RedisClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedCardinality;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IrisUserTaskRecordServiceImpl extends EsDataOperateService implements IrisUserTaskRecordService {

    @Resource
    private TIrisUserTaskRecordMapper userTaskRecordMapper;

    @Resource
    private TIrisActivityAwardRecordMapper activityAwardRecordMapper;

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private IdCreateorUtil idCreateorUtil;

    @Resource
    private IrisActivityTaskService irisActivityTaskService;

    @Resource
    private ActivityConfig activityConfig;

    @Resource
    private ActivityCommonService activityCommonService;

    @Resource
    private ActivityCommonUtilService activityCommonUtilService;

    @Value("${env.es.task.record.index.name:user-task-record}")
    private String indexName;

    @Resource
    private AwardStaticConvert awardStaticConvert;

    @Resource(name = IrisThreadPoolConfig.IRIS_FRESH_DATA_THREAD_EXECUTOR)
    private Executor irisFreshDataThreadExecutor;

    @Resource
    private UserCoreDependency userCoreDependency;

    @Resource
    private GroupTaskDependency groupTaskDependency;

    @Resource
    private DependencyConfig dependencyConfig;

    private RateLimiter FRESH_DATA_RATELIMITER = RateLimiter.create(20);

    @Resource
    private AwardMonitorService awardMonitorService;

    @Resource
    private RedisClient redisClient;

    @Resource
    private IrisEventHandingRecordService irisEventHandingRecordService;

    @Resource
    private IrisUserActivityRecordService irisUserActivityRecordService;

    @Override
    protected String[] indices() {
        return new String[]{indexName};
    }

    @Override
    public PaginationResponse<UserTaskRecordResponse> userTaskPage(PaginationRequest<UserTaskRecordRequest> request) {

        Integer pageSize = request.getPageSize();
        Integer pageNum = request.getPageNum();

        PaginationResponse<UserTaskRecordResponse> res = new PaginationResponse<>();
        res.setPageNum(pageNum);
        res.setPageSize(pageSize);
        res.setTotalCount(0);
        res.setDataList(Collections.emptyList());

        SearchResponse searchResponse = firstSearch(request);
        List<String> responseList = ESUtils.getFieldList(searchResponse, TIrisUserTaskRecordExample.UID, String.class);
        if (CollectionUtil.isEmpty(responseList)) {
            return res;
        }

        ParsedCardinality cardinality = searchResponse.getAggregations().get("totalCount");
        res.setTotalCount((int) cardinality.getValue());

        List<UserTaskRecordResponse> responses = secondSearch(request, responseList);
        res.setDataList(responses);

        if (CollectionUtil.isEmpty(responses)) {
            return res;
        }

        assembleRsp(responses);

        return res;
    }

    @Override
    public PaginationResponse<UserTaskRecordResponse> getJuniorTaskRecordList(PaginationRequest<GetJuniorTaskRecordListRequest> request) {
        Integer pageSize = request.getPageSize();
        Integer pageNum = request.getPageNum();
        PaginationResponse<UserTaskRecordResponse> res = new PaginationResponse<>();
        res.setPageNum(pageNum);
        res.setPageSize(pageSize);
        res.setTotalCount(0);
        res.setDataList(Collections.emptyList());

        // es查询活动记录
        PaginationResponse<TIrisUserActivityRecordDO> userActivityRsp = irisUserActivityRecordService.queryActivityRecordFromEs(request);
        log.info("从es获取活动记录成功：{}", JSON.toJSONString(userActivityRsp));
        if (Objects.isNull(userActivityRsp) || CollectionUtils.isEmpty(userActivityRsp.getDataList())) {
            return res;
        }
        res.setTotalCount(userActivityRsp.getTotalCount());

        // es查询任务记录
        List<TIrisUserActivityRecordDO> userActivityList = userActivityRsp.getDataList();
        List<UserTaskRecordResponse> userTaskRecordList = getUserTaskRecordByActivityList(userActivityList, request);
        log.info("从es获取任务记录成功：{}", JSON.toJSONString(userTaskRecordList));
        if (CollectionUtil.isEmpty(userTaskRecordList)) {
            return res;
        }

        List<UserTaskRecordResponse> userTaskRecordSortedList = sortUserTaskRecordResponse(userTaskRecordList, userActivityList);
        res.setDataList(userTaskRecordSortedList);

        assembleRsp(userTaskRecordSortedList);
        return res;
    }

    @Override
    public long queryContributedUserCount(String uid, String monthStr) {
        DateTime dateTime = DateUtil.parse(monthStr, "yyyyMM");
        DateTime begin = DateUtil.beginOfMonth(dateTime);
        DateTime end = DateUtil.endOfMonth(dateTime);

        InviteGiftVersionEnum inviteGiftVersion = activityCommonUtilService.getInviteGiftVersion(false, begin.getTime(), end.getTime());
        if (Objects.equals(inviteGiftVersion, InviteGiftVersionEnum.V0706)) {
            if (activityConfig.isCountAwardFromActivityRecord()) {
                return irisUserActivityRecordService.queryAwardTotalByPid(uid, dateTime);
            }
            return queryAwardTotalByPid(uid, dateTime);
        }

        ActivityUserStaticRequest countReq = new ActivityUserStaticRequest();
        countReq.setActivityTypes(Arrays.asList(ActivityTypeEnum.INVITE_GIFT));
        countReq.setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT));
        countReq.setTaskIds(Arrays.asList(ActivityTaskIdEnum.INVITE_GMV_TASK));
        countReq.setParticipated(IsParticipatedEnum.YES);
        countReq.setUid(uid);
        countReq.setStartTime(Optional.ofNullable(begin).map(Date::getTime).orElse(null));
        countReq.setEndTime(Optional.ofNullable(end).map(Date::getTime).orElse(null));
        countReq.setInviteGiftVersion(inviteGiftVersion);
        countReq.setQueryCurrentTaskStartTime(true);
        return countDistinctUid(countReq);
    }

    @Override
    public Integer queryAwardTotalByPid(String pid, Date date) {
        String inviteAwardLimitCacheKey = String.format(ActivityConfigConstants.IRIS_INVITE_UPPER_RECORD_AWARD_LIMIT_CACHE_KEY, pid,
                DateUtil.format(date, "yyyyMM"));
        String s = redisClient.get(inviteAwardLimitCacheKey);
        if (StringUtils.isNotBlank(s)) {
            log.info("queryAwardTotalByPid redis ,pid:{},value:{}", pid, s);
            return Integer.parseInt(s);
        }
        DateTime begin = DateUtil.beginOfMonth(date);
        DateTime end = DateUtil.endOfMonth(date);
        ActivityUserStaticRequest countReq = new ActivityUserStaticRequest();
        countReq.setActivityTypes(Arrays.asList(ActivityTypeEnum.INVITE_GIFT));
        countReq.setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT));
        countReq.setTaskIds(Arrays.asList(ActivityTaskIdEnum.INVITE_GMV_TASK));
        countReq.setUid(pid);
        countReq.setStartTime(begin.getTime());
        countReq.setEndTime(end.getTime());
        countReq.setQueryCurrentTaskStartTime(true);
        countReq.setAwardIssueStatus(Arrays.asList(TaskRecordAwardIssueStatusEnum.ISSUE_SUCCEED.getCode()
                , TaskRecordAwardIssueStatusEnum.ISSUE_FAILED.getCode()));
        //查询的是活动的贡献次数
        Integer awardTotal = Math.toIntExact(countDistinctUid(countReq));
        redisClient.set(inviteAwardLimitCacheKey, awardTotal.toString());
        return awardTotal;
    }

    @Override
    public long countDistinctUid(ActivityUserStaticRequest request) {
        TaskRecordRequest staticRequest = awardStaticConvert.buildFromActivityUserStaticRequest(request);
        BoolQueryBuilder query = getCommonQuery(staticRequest);
        return esCountDistinctPrecise(query, TIrisUserTaskRecordExample.UID, request.getUid(),
                esConfig.getMaxPreciseCount());
    }

    @Override
    public PaginationResponse<UserTaskRecordResponse> userTaskPageDb(
            PaginationRequest<QueryUserTaskRecordPageRequest> request) {
        PaginationResponse paginationResponse = new PaginationResponse();
        paginationResponse.setPageNum(request.getPageNum());
        paginationResponse.setPageSize(request.getPageSize());

        QueryUserTaskRecordPageRequest params = request.getQueryCriteria();
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        Criteria criteria = example.createCriteria()
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.doSharding(params.getUid()))
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, params.getUid());
        if (StringUtils.isNotEmpty(params.getPid())) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.PID, params.getPid());
        }
        if (Objects.nonNull(params.getStartTime())) {
            criteria.andPropertyGreaterThanOrEqualTo(TIrisUserTaskRecordExample.CURRENT_TASK_START_TIME,
                    params.getStartTime());
        }
        if (Objects.nonNull(params.getEndTime())) {
            criteria.andPropertyLessThanOrEqualTo(TIrisUserTaskRecordExample.CURRENT_TASK_END_TIME,
                    params.getEndTime());
        }
        if (CollectionUtil.isNotEmpty(params.getActivityIdList())) {
            criteria.andPropertyIn(TIrisUserTaskRecordExample.ACTIVITY_ID, params.getActivityIdList());
        }
        if (CollectionUtil.isNotEmpty(params.getTaskIdList())) {
            criteria.andPropertyIn(TIrisUserTaskRecordExample.TASK_ID, params.getTaskIdList());
        }
        if (CollectionUtil.isNotEmpty(params.getUserTaskStatusList())) {
            criteria.andPropertyIn(TIrisUserTaskRecordExample.USER_TASK_STATUS, params.getUserTaskStatusList());
        }
        if (StringUtils.isNotBlank(params.getPeriod())) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_PERIOD, params.getPeriod());
        }
        long count = userTaskRecordMapper.countByExample(example);
        paginationResponse.setTotalCount(((Long) count).intValue());

        int offset = (request.getPageNum() - 1) * request.getPageSize();
        int limit = request.getPageSize();
        List<TIrisUserTaskRecordDO> irisUserTaskRecordDOS = userTaskRecordMapper
                .limitSelectByExample(example, offset, limit);
        if (CollectionUtils.isNotEmpty(irisUserTaskRecordDOS)) {
            List<UserTaskRecordResponse> list = irisUserTaskRecordDOS.stream()
                    .map(n -> UserTaskRecordConvert.do2Response(n))
                    .collect(Collectors.toList());
            paginationResponse.setDataList(list);
        }

        return paginationResponse;
    }

    @Override
    public TIrisUserTaskRecordDO queryUserTaskRecord(QueryUserTaskRecordFromDBRequest request) {
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        Criteria criteria = example.createCriteria()
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, request.getUid())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, request.getActivityId())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_ID, request.getTaskId())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(request.getUid()));
        if (request.getUserTaskStatus() != null) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.USER_TASK_STATUS, request.getUserTaskStatus());
        }
        if (request.getEstimateUserTaskStatus() != null) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.ESTIMATE_USER_TASK_STATUS,
                    request.getEstimateUserTaskStatus());
        }
        if (StringUtils.isNotBlank(request.getPeriod())) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_PERIOD, request.getPeriod());
        }
        List<TIrisUserTaskRecordDO> irisUserTaskRecordDOS = userTaskRecordMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(irisUserTaskRecordDOS)) {
            return irisUserTaskRecordDOS.get(0);
        }
        return null;
    }

    @Override
    public List<TIrisUserTaskRecordDO> queryActivityTaskRecords(String uid, String activityId, String period) {

        boolean registerActivity = Objects.equals(activityId, ActivityIdEnum.REGIST_GIFT.getCode());
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        Criteria criteria = example.createCriteria()
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.STATUS, EYesNo.NO.getValue())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, activityId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(uid));
        if (period != null && !registerActivity) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_PERIOD, period);
        }
        if (registerActivity) {
            example.setOrderByClause("id desc");
            return userTaskRecordMapper.limitSelectByExample(example, 0, 1);
        }
        return userTaskRecordMapper.selectByExample(example);
    }

    @Override
    public int updateTaskRecordActivityRecordId(String uid, String activityId, String period, String taskId, String activityRecordId) {
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        Criteria criteria = example.createCriteria()
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, activityId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(uid));
        boolean registerActivity = Objects.equals(activityId, ActivityIdEnum.REGIST_GIFT.getCode());
        if (period != null && !registerActivity) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_PERIOD, period);
        }
        if (StrUtil.isNotBlank(taskId)) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_ID, taskId);
        }
        TIrisUserTaskRecordDO record = new TIrisUserTaskRecordDO();
        record.setActivityRecordId(activityRecordId);
        int i = userTaskRecordMapper.updateByExampleSelective(record, example);
        log.info("updateTaskRecordActivityRecordId 成功更新任务记录的关联活动记录id{}条，uid:{},activityId:{},period:{}.activityRecordId:{}",
                i, uid, activityId, period, activityRecordId);
        return i;
    }

    @Override
    public void updateUserTaskRecordStatus(TIrisUserTaskRecordDO userTaskRecordDO,
                                           TIrisActivityAwardRecordDO awardRecordDO) {
        //更新任务进度记录
        String bizId = userTaskRecordDO.getBizId();
        Integer shardingId = userTaskRecordDO.getShardingId();
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.createCriteria().andPropertyEqualTo(TIrisUserTaskRecordExample.BIZ_ID, bizId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, shardingId);
        TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
        updateDO.setUserTaskStatus(userTaskRecordDO.getUserTaskStatus());
        updateDO.setEstimateUserTaskStatus(userTaskRecordDO.getEstimateUserTaskStatus());
        updateDO.setAwardIssueStatus(userTaskRecordDO.getAwardIssueStatus());
        updateDO.setCommission(userTaskRecordDO.getCommission());
        updateDO.setEstimateCommission(userTaskRecordDO.getEstimateCommission());
        updateDO.setShareCount(userTaskRecordDO.getShareCount());
        updateDO.setGmv(userTaskRecordDO.getGmv());
        updateDO.setOrderFinishTime(userTaskRecordDO.getOrderFinishTime());
        updateDO.setIsParticipated(userTaskRecordDO.getIsParticipated());
        updateDO.setExtInfo(userTaskRecordDO.getExtInfo());
        updateDO.setUpdateTime(new Date());

        Integer awardValue = activityCommonUtilService.handleTaskAwardValue(userTaskRecordDO);
        updateDO.setSendAward(awardValue);

        updateDO.setStatus(UserTaskRecordStatusEnum.NORMAL.getCode());
        if (awardRecordDO != null) {
            //新增权益发放记录
            awardRecordDO.setBizId(idCreateorUtil.genId());
            awardRecordDO.setShardingId(ShardingIdUtil.sharding(awardRecordDO.getUid()));
            activityAwardRecordMapper.insertSelective(awardRecordDO);
            if (!activityConfig.isAwardQueueStop()
                    && Objects
                    .equals(awardRecordDO.getIssueStatus(), AwardRecordIssueStatusEnum.ISSUE_SUCCEED.getCode())) {
                awardMonitorService.produce(awardRecordDO);
            }
        }
        userTaskRecordMapper.updateByExampleSelective(updateDO, example);
        log.info("更新任务状态，uid:{}, shardingId：{}，bizId：{}，任务信息：{}，发奖信息：{}", userTaskRecordDO.getUid(), shardingId, bizId,
                JSON.toJSONString(updateDO), JSON.toJSONString(awardRecordDO));
    }

    @Override
    public void deleteTaskRecord(TIrisUserTaskRecordDO userTaskRecordDO) {
        //删除任务进度记录
        String bizId = userTaskRecordDO.getBizId();
        Integer shardingId = userTaskRecordDO.getShardingId();
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.createCriteria().andPropertyEqualTo(TIrisUserTaskRecordExample.BIZ_ID, bizId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, shardingId);
        TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
        updateDO.setUserTaskStatus(userTaskRecordDO.getUserTaskStatus());
        updateDO.setEstimateUserTaskStatus(userTaskRecordDO.getEstimateUserTaskStatus());
        updateDO.setAwardIssueStatus(userTaskRecordDO.getAwardIssueStatus());
        updateDO.setCommission(userTaskRecordDO.getCommission());
        updateDO.setEstimateCommission(userTaskRecordDO.getEstimateCommission());
        updateDO.setShareCount(userTaskRecordDO.getShareCount());
        updateDO.setGmv(userTaskRecordDO.getGmv());
        updateDO.setOrderFinishTime(userTaskRecordDO.getOrderFinishTime());
        updateDO.setIsParticipated(userTaskRecordDO.getIsParticipated());
        updateDO.setExtInfo(userTaskRecordDO.getExtInfo());
        updateDO.setUpdateTime(new Date());
        updateDO.setSendAward(userTaskRecordDO.getSendAward());

        updateDO.setStatus(UserTaskRecordStatusEnum.DELETED.getCode());
        userTaskRecordMapper.updateByExampleSelective(updateDO, example);
        log.info("删除任务记录，uid:{}, shardingId：{}，bizId：{}，任务信息：{}", userTaskRecordDO.getUid(), shardingId, bizId, JSON.toJSONString(updateDO));
    }

    @Override
    public void updateUserTaskStartTime(TIrisUserTaskRecordDO userTaskRecord) {
        //更新任务进度记录
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.createCriteria().andPropertyEqualTo(TIrisUserTaskRecordExample.BIZ_ID, userTaskRecord.getBizId())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, userTaskRecord.getShardingId());
        TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
        updateDO.setCurrentTaskStartTime(userTaskRecord.getCurrentTaskStartTime());
        updateDO.setUpdateTime(new Date());
        userTaskRecordMapper.updateByExampleSelective(updateDO, example);
    }

    @Override
    public void saveUserTaskRecord(TIrisUserTaskRecordDO userTaskRecordDO) {
        userTaskRecordDO.setShardingId(ShardingIdUtil.sharding(userTaskRecordDO.getUid()));
        userTaskRecordMapper.insertSelective(userTaskRecordDO);
    }

    /**
     * 第二次搜索，查询所有参与记录
     *
     * @param request
     * @param uidList
     * @return
     */
    private List<UserTaskRecordResponse> secondSearch(PaginationRequest<UserTaskRecordRequest> request,
                                                      List<String> uidList) {
        SearchRequest searchRequest = new SearchRequest(indexName);
        UserTaskRecordRequest queryCriteria = request.getQueryCriteria();
        String pid = queryCriteria.getUid();

        BoolQueryBuilder query = buildUidQuery(queryCriteria, uidList);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(query)
                .size(esConfig.getMaxPageSize());
        searchRequest.source(sourceBuilder).routing(pid);

        SearchResponse searchResponse = null;
        try {
            log.info("第二次搜素任务记录表，搜索参数：{}", searchRequest);
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("第二次搜素任务记录表错误，搜索参数：{}", searchRequest, e);
        }
        AssertUtils.isNotNull(searchResponse, IrisErrorCode.OPERATE_FAIL);

        log.info("第二次搜素任务记录表成功，搜索参数：{}，返回：{}", searchRequest, searchResponse);
        return ESUtils.buildResponse(searchResponse, UserTaskRecordResponse.class);
    }

    private List<UserTaskRecordResponse> getUserTaskRecordByActivityList(List<TIrisUserActivityRecordDO> dataList,
                                                                         PaginationRequest<GetJuniorTaskRecordListRequest> request) {
        List<String> bizIdList = new ArrayList<>(dataList.size());
        dataList.forEach(userActivity -> {
            bizIdList.add(userActivity.getBizId());
        });

        GetJuniorTaskRecordListRequest queryCriteria = request.getQueryCriteria();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        String pid = queryCriteria.getPid();
        query.must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.PID, pid))
                .must(QueryBuilders.termsQuery("activityRecordId", bizIdList))
                .must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.STATUS, EYesNo.NO.getValue()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(query)
                .size(esConfig.getMaxPageSize());
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(sourceBuilder).routing(pid);

        SearchResponse searchResponse = null;
        try {
            log.info("获取下级任务列表搜素任务记录表，搜索参数：{}", searchRequest);
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("获取下级任务列表搜素任务记录表错误，搜索参数：{}", searchRequest, e);
        }
        AssertUtils.isNotNull(searchResponse, IrisErrorCode.OPERATE_FAIL);

        log.info("获取下级任务列表搜素任务记录表成功，搜索参数：{}，返回：{}", searchRequest, searchResponse);
        return ESUtils.buildResponse(searchResponse, UserTaskRecordResponse.class);
    }

    /**
     * 搜索去重任务下级uid
     *
     * @param request
     * @return
     */
    private SearchResponse firstSearch(PaginationRequest<UserTaskRecordRequest> request) {
        SearchRequest searchRequest = new SearchRequest(indexName);
        UserTaskRecordRequest queryCriteria = request.getQueryCriteria();
        String pid = queryCriteria.getUid();

        BoolQueryBuilder query = buildUidQuery(queryCriteria);

        //从第几条开始
        Integer pageSize = request.getPageSize();
        Integer pageNum = request.getPageNum();
        int from = pageSize * (pageNum - 1);

        AggregationBuilder aggregation = AggregationBuilders.cardinality("totalCount")
                .field(TIrisUserTaskRecordExample.UID).precisionThreshold(Integer.MAX_VALUE);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(query)
                .collapse(new CollapseBuilder(TIrisUserTaskRecordExample.UID)).from(from).size(pageSize)
                .aggregation(aggregation).fetchSource(new String[]{TIrisUserTaskRecordExample.UID}, null);
        searchRequest.source(sourceBuilder).routing(pid);

        //分页去重查询任务记录的下级uid
        SearchResponse searchResponse = null;
        try {
            log.info("首次分页去重搜素任务记录表uid，搜索参数：{}", searchRequest);
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("首次分页去重搜素任务记录表uid错误：搜索参数：{}", searchRequest, e);
        }
        AssertUtils.isNotNull(searchResponse, IrisErrorCode.OPERATE_FAIL);

        log.info("首次分页去重搜素任务记录表uid成功，搜索参数：{}，返回：{}", searchRequest, searchResponse);
        return searchResponse;
    }

    private BoolQueryBuilder buildUidQuery(UserTaskRecordRequest request) {
        return buildUidQuery(request, null);
    }

    /**
     * 构建查询，不包含注册有礼，升级有礼(晋升奖)
     *
     * @return
     */
    private BoolQueryBuilder buildUidQuery(UserTaskRecordRequest request, List<String> uidList) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();

        String uid = request.getUid();
        List<String> activityTypes = Optional.ofNullable(
                        request.getActivityTypeList()).orElseGet(ArrayList::new).stream()
                .filter(i -> StrUtil.isNotBlank(i) && !Objects.equals(i, ActivityTypeEnum.REGIST_GIFT.getCode())
                        && !Objects.equals(i, ActivityTypeEnum.LEVEL_UP_PROMO_GIFT.getCode()))
                .collect(Collectors.toList());
        Long createTime = request.getCreateTime();
        //pid搜索，是否失效为否
        query.must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.PID, uid))
                .must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.STATUS, EYesNo.NO.getValue()));

        //活动类型搜索
        if (CollectionUtil.isNotEmpty(activityTypes)) {
            query.must(QueryBuilders.termsQuery("activityType", activityTypes));
        } else {
            //会员任务不展示注册有礼任务,升级有礼(晋升奖)
            query.mustNot(QueryBuilders.termsQuery("activityType",
                    ActivityTypeEnum.REGIST_GIFT.getCode(), ActivityTypeEnum.LEVEL_UP_PROMO_GIFT.getCode()));
        }

        //时间搜索
        if (createTime != null) {
            DateTime date = DateUtil.date(createTime);
            DateTime begin = DateUtil.beginOfMonth(date);
            DateTime end = DateUtil.endOfMonth(date);
            query.must(QueryBuilders.rangeQuery("createTime").gte(begin.getTime()).lte(end.getTime()));
        }

        if (CollectionUtil.isNotEmpty(uidList)) {
            query.must(QueryBuilders.termsQuery(TIrisUserTaskRecordExample.UID, uidList));
        }

        return query;
    }

    @Override
    public LongTermAwardStaticResponse longTermAwardStatic(LongTermAwardStaticRequest request) {
        AwardStaticRequest awardStaticRequest = awardStaticConvert.buildFromLongTermAwardStaticRequest(request);
        awardStaticRequest.setActivityTypes(Arrays.asList(ActivityTypeEnum.MONTH_GIFT));
        AwardStaticResponse awardStaticResponse = getAwardStaticResponse(awardStaticRequest);
        LongTermAwardStaticResponse termAwardStaticResponse = awardStaticConvert
                .buildLongTermAwardStaticResponse(awardStaticResponse);

        TaskRecordRequest taskRecordRequest = awardStaticConvert
                .buildTaskRecordRequestFromLongTermAwardStaticRequest(request);
        taskRecordRequest.setActivityTypes(Arrays.asList(ActivityTypeEnum.MONTH_GIFT));
        List<TaskCommissionDetailResponse> waitTaskPhaseData = getWaitTaskPhaseData(taskRecordRequest);
        termAwardStaticResponse.setTaskCommissionDetails(waitTaskPhaseData);
        return termAwardStaticResponse;
    }

    @Override
    public AwardStaticResponse awardStatic(AwardStaticRequest request) {
        return getAwardStaticResponse(request);
    }

    @Override
    public List<TaskCommissionDetailResponse> getWaitTaskPhaseData(TaskRecordRequest request) {
        //待确认收益明细
        BoolQueryBuilder commonQuery = getCommonQuery(request);
        commonQuery.must(QueryBuilders.termQuery(
                        StrUtil.toCamelCase(TIrisUserTaskRecordExample.ESTIMATE_USER_TASK_STATUS),
                        TaskEstimateStatusEnum.FINISHED.getCode()))
                .must(QueryBuilders.boolQuery()
                        .should(QueryBuilders.boolQuery()
                                .mustNot(QueryBuilders
                                        .termQuery(StrUtil.toCamelCase(TIrisUserTaskRecordExample.USER_TASK_STATUS),
                                                UserTaskStatusEnum.FINISHED.getCode()))
                        )
                        .should(QueryBuilders.boolQuery()
                                .mustNot(QueryBuilders
                                        .termQuery(StrUtil.toCamelCase(TIrisUserTaskRecordExample.AWARD_ISSUE_STATUS),
                                                TaskRecordAwardIssueStatusEnum.ISSUE_SUCCEED.getCode())))
                );

        FieldSortBuilder sortBuilder = SortBuilders
                .fieldSort(StrUtil.toCamelCase(TIrisUserTaskRecordExample.CREATE_TIME));
        EsQueryDTO esQueryDTO = EsQueryDTO.builder().query(commonQuery).routing("0")
                .pageNum(1).pageSize(esConfig.getMaxPageSize()).sortBuilder(sortBuilder).build();

        Function<SearchResponse, List<TIrisUserTaskRecordDO>> func = (r) -> ESUtils
                .buildResponse(r, TIrisUserTaskRecordDO.class);
        List<TIrisUserTaskRecordDO> records = searchList(esQueryDTO, func);
        if (CollectionUtil.isEmpty(records)) {
            return Collections.emptyList();
        }

        List<String> taskIds = records.stream().map(TIrisUserTaskRecordDO::getTaskId)
                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<TIrisActivityTaskDO> tasks = irisActivityTaskService.getTasksByIds(taskIds);
        Map<String, TIrisActivityTaskDO> taskMap = tasks.stream().collect(Collectors.toMap(
                TIrisActivityTaskDO::getBizId, i -> i, (i1, i2) -> i1));

        //根据taskId，月份，阶段聚合
        Map<String, List<TIrisUserTaskRecordDO>> map = records.stream()
                .collect(Collectors.groupingBy(i -> getTaskGroupKey(i), LinkedHashMap::new, Collectors.toList()));
        return map.entrySet().stream().map(i -> {
            int size = i.getValue().size();
            TIrisUserTaskRecordDO taskRecord = i.getValue().get(0);

            TIrisActivityTaskDO task = taskMap.get(taskRecord.getTaskId());
            AwardInfoDTO awardInfo = activityCommonService.getAwardInfoCacheByMarket(task.getAwardInfo());
            return new TaskCommissionDetailResponse()
                    .setTaskId(task.getBizId())
                    .setTaskName(getTaskName(task, taskRecord))
                    .setPredictAwardAmount(Optional.ofNullable(awardInfo.getValue()).orElse(0) * size);
        }).collect(Collectors.toList());
    }

    /**
     * 获取分组key
     *
     * @param taskRecord
     * @return
     */
    private String getTaskGroupKey(TIrisUserTaskRecordDO taskRecord) {
        return new StringBuilder(taskRecord.getTaskId()).append("@")
                .append(DateUtil.format(taskRecord.getCurrentTaskStartTime(), "MM"))
                .append("@").append(taskRecord.getTier()).toString();
    }

    /**
     * 获取任务名称
     *
     * @param taskRecord
     * @return
     */
    private String getTaskName(TIrisActivityTaskDO task, TIrisUserTaskRecordDO taskRecord) {
        return new StringBuilder(task.getName()).append("-")
                .append(DateUtil.format(taskRecord.getCurrentTaskStartTime(), "MM月-"))
                .append(taskRecord.getTier()).append("阶").toString();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateUserTaskRecord(UpdateUserTaskRecordRequest request) {
        if (!activityConfig.getTestUidWhiteList().contains(request.getUid())) {
            throw new TRetailBizException("当前用户不是白名单用户，不能调整任务参与记录");
        }
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.createCriteria().andPropertyEqualTo(TIrisUserTaskRecordExample.BIZ_ID, request.getRecordBizId())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, request.getUid())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID,
                        ShardingIdUtil.doSharding(request.getUid()));
        TIrisUserTaskRecordDO updateDO = new TIrisUserTaskRecordDO();
        updateDO.setUpdateTime(new Date());
        updateDO.setUserTaskStatus(request.getUserTaskStatus());
        updateDO.setCurrentTaskStartTime(request.getCurrentTaskStartTime());
        updateDO.setCurrentTaskEndTime(request.getCurrentTaskEndTime());
        int i = userTaskRecordMapper.updateByExampleSelective(updateDO, example);
        if (i != 1) {
            throw new TRetailBizException("更新了多条记录，回滚db变更");
        }
        return true;
    }

    /**
     * 统计预估收益和实际收益
     *
     * @param request
     * @return
     */
    private AwardStaticResponse getAwardStaticResponse(AwardStaticRequest request) {
        AwardStaticResponse response = new AwardStaticResponse();

        long estimateCommission = 0;
        long commission = 0;

        String uid = request.getUid();
        //确认奖励金
        TaskRecordRequest staticRequest = awardStaticConvert.buildFromAwardStaticRequest(request);
        if (request.getOldInviteData() != null) {
            InviteGiftVersionEnum inviteGiftVersion = activityCommonUtilService.getInviteGiftVersion(request.getOldInviteData(),
                    request.getStartTime(), request.getEndTime());
            staticRequest.setInviteGiftVersion(inviteGiftVersion);
            staticRequest.setQueryCurrentTaskStartTime(true);
        }
        if (CollectionUtil.contains(request.getActivityIds(), ActivityIdEnum.INVITE_GIFT)
                || (CollectionUtil.isEmpty(request.getActivityIds())
                && CollectionUtil.contains(request.getActivityTypes(), ActivityTypeEnum.INVITE_GIFT))) {
            staticRequest.setQueryCurrentTaskStartTime(true);
        }
        staticRequest.setParticipated(IsParticipatedEnum.YES);

        //确认奖励金 按月-task统计
        BoolQueryBuilder commonQuery = getCommonQuery(staticRequest);
        commonQuery.must(QueryBuilders.termQuery(StrUtil.toCamelCase(
                TIrisUserTaskRecordExample.USER_TASK_STATUS), UserTaskStatusEnum.FINISHED.getCode()));
        commonQuery.must(QueryBuilders.termQuery(StrUtil.toCamelCase(
                TIrisUserTaskRecordExample.AWARD_ISSUE_STATUS), TaskRecordAwardIssueStatusEnum.ISSUE_SUCCEED.getCode()));
        Map<ZonedDateTime, Map<String, Long>> monthTaskMap = queryMonthTaskMap(uid, commonQuery);

        //预估奖励金
        commonQuery = getCommonQuery(staticRequest);
        // 预估已完成
        commonQuery.must(QueryBuilders.termQuery(StrUtil.toCamelCase(TIrisUserTaskRecordExample.ESTIMATE_USER_TASK_STATUS),
                        TaskEstimateStatusEnum.FINISHED.getCode()));
        Map<ZonedDateTime, Map<String, Long>> estimateMonthTaskMap = queryMonthTaskMap(uid, commonQuery);

        if (CollectionUtil.isEmpty(monthTaskMap)
                && CollectionUtil.isEmpty(estimateMonthTaskMap)) {
            return response.setCommission(0L)
                    .setEstimateCommission(0L).setTbcCommission(0L);
        }

        //查询月份限额
        List<String> limitedTaskIds = activityConfig.getLimitedActivity().entrySet().stream()
                .flatMap(i -> i.getValue().stream()).collect(Collectors.toList());
        //受限的taskId才需要查询月份限额
        List<Date> monthList = estimateMonthTaskMap.entrySet().stream()
                .filter(i -> CollectionUtil.containsAny(i.getValue().keySet(), limitedTaskIds))
                .map(i -> DateUtil.date(i.getKey().withZoneSameInstant(ZoneId.systemDefault()).toInstant().toEpochMilli())).collect(Collectors.toList());
        Map<String, Map<String, Integer>> monthLimitMap = activityCommonService.queryInviteLimitMap(Arrays.asList(uid), monthList);
        Map<String, Integer> limitMap = monthList.stream().distinct().collect(Collectors.toMap(
                i -> DateUtil.format(i, "yyyyMM"), i -> {
                    Integer limit = monthLimitMap.getOrDefault(DateUtil.format(i, "yyyyMM"), Collections.emptyMap()).get(uid);
                    return Optional.ofNullable(limit).orElse(-1);
                }
        ));

        List<String> taskIds = Lists.newArrayList();
        taskIds.addAll(monthTaskMap.values().stream().flatMap(i -> i.keySet().stream()).collect(Collectors.toList()));
        taskIds.addAll(estimateMonthTaskMap.values().stream().flatMap(i -> i.keySet().stream()).collect(Collectors.toList()));
        List<TIrisActivityTaskDO> tasks = irisActivityTaskService.getTasksByIds(taskIds);

        Map<String, Integer> taskAwardInfoMap = tasks.stream().collect(Collectors.toMap(
                TIrisActivityTaskDO::getBizId, i -> {
                    AwardInfoDTO awardInfo = activityCommonService.getAwardInfoCacheByMarket(i.getAwardInfo());
                    return Optional.ofNullable(awardInfo).map(AwardInfoDTO::getValue).orElse(0);
                }, (i1, i2) -> i1));

        estimateCommission = handleEstimateCommission(monthTaskMap, estimateMonthTaskMap, taskAwardInfoMap, limitMap);
        commission = handleCommission(monthTaskMap);

        response.setCommission(commission)
                .setEstimateCommission(estimateCommission)
                .setTbcCommission(estimateCommission - commission);
        log.info("搜索{}奖励金结果：{}，限制上限：{}", uid, JSON.toJSONString(response), JSON.toJSONString(limitMap));
        return response;
    }

    /**
     * 处理确认奖励金
     *
     * @param monthTaskMap
     * @return
     */
    private long handleCommission(Map<ZonedDateTime, Map<String, Long>> monthTaskMap) {
        long commission = 0L;
        for (Map<String, Long> taskMap : monthTaskMap.values()) {
            for (Map.Entry<String, Long> entry : taskMap.entrySet()) {
                Long countValue = entry.getValue();
                // 直接累加每个月的实际奖励
                commission += countValue;
            }
        }
        return commission;
    }

    private long handleEstimateCommission(Map<ZonedDateTime, Map<String, Long>> monthTaskMap,
                                          Map<ZonedDateTime, Map<String, Long>> estimateMonthTaskMap,
                                          Map<String, Integer> taskAwardInfoMap, Map<String, Integer> limitMap) {
        long estimateCommission = 0L;
        for (Map.Entry<ZonedDateTime, Map<String, Long>> entry : estimateMonthTaskMap.entrySet()) {
            ZonedDateTime key = entry.getKey();
            String monthStr = key.format(DateTimeFormatter.ofPattern("yyyyMM").withZone(ZoneId.systemDefault()));
            Integer monthLimit = limitMap.get(monthStr);
            Map<String, Long> estimateTaskSumMap = entry.getValue();
            Map<String, Long> taskSumMap = monthTaskMap.getOrDefault(key, Collections.emptyMap());
            for (Map.Entry<String, Long> eTaskCount : estimateTaskSumMap.entrySet()) {
                String taskId = eTaskCount.getKey();
                Long estimateTaskSum = eTaskCount.getValue();
                Long taskSum = taskSumMap.getOrDefault(taskId, 0L);

                // 存在限额
                if (monthLimit != null && monthLimit > 0) {
                    // 最大预估奖励与预估奖励比较，两者取更小
                    Integer awardValue = taskAwardInfoMap.getOrDefault(taskId, 0);
                    long maxValue = (long) monthLimit * awardValue;
                    estimateCommission += Math.min(Math.max(taskSum, estimateTaskSum), maxValue);
                } else {
                    // 预估奖励与实际奖励比较，两者取最大
                    estimateCommission += Math.max(taskSum, estimateTaskSum);
                }
            }
        }
        return estimateCommission;
    }

    /**
     * 按月份-taskId分组统计任务完成情况
     *
     * @param commonQuery
     * @return
     */
    private Map<ZonedDateTime, Map<String, Long>> queryMonthTaskMap(String uid, BoolQueryBuilder commonQuery) {
        TermsAggregationBuilder termsAgg = AggregationBuilders.terms("taskGroup").minDocCount(1)
                .field(StrUtil.toCamelCase(TIrisUserTaskRecordExample.TASK_ID)).size(esConfig.getTermsSize()).shardSize(esConfig.getTermsSize());

        SumAggregationBuilder taskSum = AggregationBuilders.sum("task_sum")
                .field(StrUtil.toCamelCase(TIrisUserTaskRecordExample.SEND_AWARD));
        termsAgg.subAggregation(taskSum);

        DateHistogramAggregationBuilder aggregation = AggregationBuilders.dateHistogram("month_commission")
                .field(StrUtil.toCamelCase(TIrisUserTaskRecordExample.CURRENT_TASK_START_TIME)).minDocCount(1)
                .calendarInterval(DateHistogramInterval.MONTH).offset("-8h").subAggregation(termsAgg);

        EsQueryDTO esQueryDTO = EsQueryDTO.builder().query(commonQuery).routing(uid).totalAggregation(aggregation)
                .pageNum(0).pageSize(0).build();

        SearchResponse searchResponse = getSearchResponse(esQueryDTO);
        Aggregations aggregations = searchResponse.getAggregations();
        ParsedDateHistogram monthAggregations = aggregations.get(aggregation.getName());
        if (monthAggregations == null && CollectionUtil.isEmpty(monthAggregations.getBuckets())) {
            return Collections.emptyMap();
        }

        List<ParsedDateHistogram.ParsedBucket> buckets = (List<ParsedDateHistogram.ParsedBucket>) monthAggregations.getBuckets();
        Map<ZonedDateTime, Map<String, Long>> monthTaskMap = Maps.newHashMapWithExpectedSize(buckets.size());
        for (ParsedDateHistogram.ParsedBucket bucket : buckets) {
            ZonedDateTime dateTime = (ZonedDateTime) bucket.getKey();
            ParsedStringTerms termsAggRes = bucket.getAggregations().get(termsAgg.getName());
            List<? extends Terms.Bucket> buckets1 = termsAggRes.getBuckets();
            Map<String, Long> taskMap = Maps.newHashMapWithExpectedSize(buckets1.size());
            for (Terms.Bucket bucket1 : buckets1) {
                // 获取求和
                Aggregations aggregations1 = bucket1.getAggregations();
                Sum sum = aggregations1.get(taskSum.getName());
                taskMap.put(bucket1.getKeyAsString(), (long) sum.getValue());
            }
            monthTaskMap.put(dateTime, taskMap);
        }
        return monthTaskMap;
    }

    /**
     * @param request
     * @return
     */
    private BoolQueryBuilder getCommonQuery(TaskRecordRequest request) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.PID, request.getUid()))
                .must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.STATUS, EYesNo.NO.getValue()));
        //任务类型
        List<ActivityTypeEnum> activityTypes = request.getActivityTypes();
        if (CollectionUtil.isNotEmpty(activityTypes)) {
            List<String> types = activityTypes.stream().map(ActivityTypeEnum::getCode).collect(Collectors.toList());
            queryBuilder.must(QueryBuilders.termsQuery("activityType", types));
        }

        //任务id
        List<ActivityIdEnum> activityIds = request.getActivityIds();
        if (CollectionUtil.isNotEmpty(activityIds)) {
            List<String> ids = activityIds.stream().map(ActivityIdEnum::getCode).collect(Collectors.toList());
            queryBuilder.must(QueryBuilders.termsQuery("activityId", ids));
        }

        //任务参与时间
        String timeField = request.isQueryCurrentTaskStartTime() ? "currentTaskStartTime" : "createTime";
        RangeQueryBuilder timeFieldQuery = QueryBuilders.rangeQuery(timeField);
        if (request.getStartTime() != null) {
            timeFieldQuery.gte(request.getStartTime());
        }
        if (request.getEndTime() != null) {
            timeFieldQuery.lte(request.getEndTime());
        }
        if (request.getStartTime() != null || request.getEndTime() != null) {
            queryBuilder.must(timeFieldQuery);
        }

        IsParticipatedEnum participated = request.getParticipated();
        if (participated != null) {
            queryBuilder.must(QueryBuilders.termQuery("isParticipated", participated.name()));
        }

        List<ActivityTaskIdEnum> taskIds = request.getTaskIds();
        if (CollectionUtil.isNotEmpty(taskIds)) {
            List<String> ids = taskIds.stream().map(ActivityTaskIdEnum::getCode).collect(Collectors.toList());
            queryBuilder.must(QueryBuilders.termsQuery("taskId", ids));
        }

        List<Byte> userTaskStatus = request.getUserTaskStatus();
        if (CollectionUtil.isNotEmpty(userTaskStatus)) {
            List<Byte> statuses = userTaskStatus.stream().filter(i -> UserTaskStatusEnum.getByCode(i) != null)
                    .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(statuses)) {
                queryBuilder.must(QueryBuilders.termsQuery("userTaskStatus", statuses));
            }
        }

        List<Byte> estimateUserTaskStatus = request.getEstimateUserTaskStatus();
        if (CollectionUtil.isNotEmpty(estimateUserTaskStatus)) {
            List<Byte> statuses = estimateUserTaskStatus.stream().filter(i -> TaskEstimateStatusEnum.getByCode(i) != null)
                    .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(statuses)) {
                queryBuilder.must(QueryBuilders.termsQuery("estimateUserTaskStatus", statuses));
            }
        }

        //邀请有礼版本号
        InviteGiftVersionEnum inviteGiftVersion = request.getInviteGiftVersion();
        if (inviteGiftVersion != null) {
            Long startTime = inviteGiftVersion.getStartTime();
            Long endTime = inviteGiftVersion.getEndTime();
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("currentTaskStartTime");
            if (startTime != null) {
                rangeQuery.gte(startTime);
            }
            if (endTime != null) {
                rangeQuery.lte(endTime);
            }
            queryBuilder.must(rangeQuery);
        }

        List<Byte> awardIssueStatus = request.getAwardIssueStatus();
        if (CollectionUtil.isNotEmpty(awardIssueStatus)) {
            queryBuilder.must(QueryBuilders.termsQuery(StrUtil.toCamelCase(TIrisUserTaskRecordExample.AWARD_ISSUE_STATUS), awardIssueStatus));
        }

        return queryBuilder;
    }

    /**
     * es count
     *
     * @param pid
     * @param query
     * @return
     */
    private Map<String, Long> esCount(String pid, QueryBuilder query) {

        Integer termsSize = esConfig.getTermsSize();
        TermsAggregationBuilder aggregation = AggregationBuilders.terms("taskGroup")
                .field("taskId").size(termsSize).shardSize(termsSize);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(query)
                .from(0).size(0).aggregation(aggregation);

        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(sourceBuilder).routing(pid);

        SearchResponse response = null;
        try {
            log.info("分组统计任务完成情况 ,参数: {}", searchRequest);
            response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("分组统计任务完成情况错误 ,参数: {}", searchRequest, e);
        }
        AssertUtils.isNotNull(response, IrisErrorCode.OPERATE_FAIL);

        log.info("分组统计任务完成情况成功 ,参数: {}，返回：{}", searchRequest, response);
        Terms taskGroup = response.getAggregations().get("taskGroup");
        return taskGroup.getBuckets().stream().collect(Collectors.toMap(
                MultiBucketsAggregation.Bucket::getKeyAsString,
                i -> i.getDocCount(), (i1, i2) -> i1));
    }

    @Override
    public ActivityUserStaticResponse activityUserStatic(ActivityUserStaticRequest request) {
        long userCount = 0;
        long contributingCount = 0;
        int limitLeft = 0;
        ActivityUserStaticResponse response = new ActivityUserStaticResponse();
        try {
            TaskRecordRequest staticRequest = awardStaticConvert.buildFromActivityUserStaticRequest(request);
            InviteGiftVersionEnum inviteGiftVersion = null;
            Boolean oldInviteData = request.getOldInviteData();
            if (oldInviteData != null) {
                inviteGiftVersion = activityCommonUtilService.getInviteGiftVersion(oldInviteData, request.getStartTime(), request.getEndTime());
                staticRequest.setInviteGiftVersion(inviteGiftVersion);
                staticRequest.setQueryCurrentTaskStartTime(true);
            }

            userCount = getUserCount(staticRequest);

            //可贡献
            contributingCount = getContributingCount(staticRequest);

            limitLeft = getLimitLeft(oldInviteData, staticRequest);

            handleVersion(response, staticRequest, inviteGiftVersion);

        } catch (Exception e) {
            log.error("统计参与活动用户数错误：搜索参数：{}", JSON.toJSONString(request), e);
            if (e instanceof TRetailBizException) {
                throw e;
            }
        }

        response.setContributingCount(Math.toIntExact(contributingCount))
                .setUserCount(Math.toIntExact(userCount))
                .setLimitLeft(limitLeft);
        log.info("统计参与活动用户数，搜索参数：{}，返回：{}", JSON.toJSONString(request), JSON.toJSONString(response));
        return response;
    }

    @Override
    public UserActivityInfoResponse userActivityInfo(UserActivityInfoRequest request) {

        String uid = request.getUid();
        UserActivityInfoResponse response = new UserActivityInfoResponse();
        MonthActivityInfoResponse monthResponse = new MonthActivityInfoResponse();
        InviteActivityInfoResponse inviteResponse = new InviteActivityInfoResponse();
        response.setInviteActivityInfo(inviteResponse).setMonthActivityInfo(monthResponse);

        Date now = new Date();
        DateTime begin = DateUtil.beginOfMonth(now);
        DateTime end = DateUtil.endOfMonth(now);

        //月月领
        AwardStaticRequest awardStaticRequest = new AwardStaticRequest()
                .setActivityIds(Arrays.asList(ActivityIdEnum.MONTH_GIFT))
                .setUid(uid).setStartTime(begin.getTime()).setEndTime(end.getTime());
        AwardStaticResponse awardStaticResponse = getAwardStaticResponse(awardStaticRequest);
        monthResponse.setAwardAmount(Math.toIntExact(Optional.ofNullable(awardStaticResponse)
                        .map(AwardStaticResponse::getCommission).orElse(0l)))
                .setEstimateAwardAmount(Math.toIntExact(Optional.ofNullable(awardStaticResponse)
                        .map(AwardStaticResponse::getEstimateCommission).orElse(0l)));

        handleMonthText(monthResponse);

        //邀请有礼
        awardStaticRequest = new AwardStaticRequest()
                .setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT))
                .setUid(uid).setStartTime(begin.getTime()).setEndTime(end.getTime());
        awardStaticResponse = getAwardStaticResponse(awardStaticRequest);
        inviteResponse.setAwardAmount(Math.toIntExact(Optional.ofNullable(awardStaticResponse)
                        .map(AwardStaticResponse::getCommission).orElse(0l)))
                .setEstimateAwardAmount(Math.toIntExact(Optional.ofNullable(awardStaticResponse)
                        .map(AwardStaticResponse::getEstimateCommission).orElse(0l)));

        AwardInfoDTO awardInfo = irisActivityTaskService.getAwardInfoByTaskBizId(ActivityTaskIdEnum.INVITE_GMV_TASK.getCode());
        inviteResponse.setAwardValue(Optional.ofNullable(awardInfo).map(AwardInfoDTO::getValue).orElse(0));

        TaskRecordRequest taskRecordRequest = new TaskRecordRequest()
                .setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT))
                .setUid(uid).setStartTime(begin.getTime()).setEndTime(end.getTime());
        int userCount = (int) getUserCount(taskRecordRequest);
        inviteResponse.setCurrentMonthInvite(userCount);

        String monthStr = YearMonth.now().format(DateTimeFormatter.ofPattern(TimeUtils.YYYYMM));
        InviteLimitDTO inviteLimitDTO = activityCommonService.queryUserInviteLimit(uid, monthStr);
        inviteResponse.setCurrentMonthLimit(Optional.ofNullable(inviteLimitDTO)
                .map(InviteLimitDTO::getInviteLimit).orElse(0));

        inviteResponse.setMaxAwardAmount(inviteResponse.getCurrentMonthLimit() * inviteResponse.getAwardValue());
        handleInviteText(inviteResponse, userCount);
        return response;
    }

    /**
     * 处理月月领文本
     *
     * @param monthResponse
     */
    private void handleMonthText(MonthActivityInfoResponse monthResponse) {
        MonthActivityInfoVO vo = new MonthActivityInfoVO();
        BeanUtil.copyProperties(monthResponse, vo);
        Map<String, List<ActivityComponentTextDTO>> map = activityConfig.getActivityComponentText().get(ActivityIdEnum.MONTH_GIFT.getCode());
        List<ActivityComponentTextDTO> textList;
        if (monthResponse.getEstimateAwardAmount() > 0) {
            //当用户当月预估奖励金大于0时，展示以下文案：
            //“本月预估得x元”——x为当前用户当前月在月月领下的预估奖励金，第一行：本月预估得；第二行：x元
            textList = map.get("hasAward");
        } else {
            //当用户当月预估奖励金=0时，展示以下文案：
            //“每月都可领 奖励无上限”——固定文案，第一行：每月都可领；第二行：奖励无上限
            textList = map.get("hasNotAward");
        }
        if (CollectionUtil.isNotEmpty(textList)) {
            int index = new Random().nextInt(textList.size());
            ActivityComponentTextDTO dto = textList.get(index);
            String text1 = SpelUtils.parse(dto.getText1(), vo, String.class);
            String text2 = SpelUtils.parse(dto.getText2(), vo, String.class);
            monthResponse.setText1(text1).setText2(text2);
        }
    }

    /**
     * 处理邀请有礼文本
     *
     * @param inviteResponse
     * @param userCount
     */
    private void handleInviteText(InviteActivityInfoResponse inviteResponse, int userCount) {
        InviteActivityInfoVO vo = new InviteActivityInfoVO();
        BeanUtil.copyProperties(inviteResponse, vo);
        Map<String, List<ActivityComponentTextDTO>> map = activityConfig.getActivityComponentText().get(ActivityIdEnum.INVITE_GIFT.getCode());
        List<ActivityComponentTextDTO> textList;
        if (userCount >= 1) {
            //当用户当月已邀请人数大于等于1人，以下两种文案随机展示：
            //“本月已邀请x人”——x为当前自然月已邀请人数，第一行：本月已邀请；第二行：x人
            //“本月最高可得y元”——y为当前访问用户等级上限*当前单人奖励金额，第一行：本月最高可得；第二行：y元
            textList = map.get("hasInvite");
        } else {
            //当用户当月已邀请人数等于0人，以下两种文案随机展示：
            //“邀1人得x元”——x为当前单人奖励金额，第一行：邀1人得；第二行：x元
            //“本月最高可得y元”——y为当前访问用户等级上限*当前单人奖励金额，第一行：本月最高可得；第二行：y元
            textList = map.get("hasNotInvite");
        }
        if (CollectionUtil.isNotEmpty(textList)) {
            int index = new Random().nextInt(textList.size());
            ActivityComponentTextDTO dto = textList.get(index);
            String text1 = SpelUtils.parse(dto.getText1(), vo, String.class);
            String text2 = SpelUtils.parse(dto.getText2(), vo, String.class);
            inviteResponse.setText1(text1).setText2(text2);
        }
    }


    @Override
    public ActivityStaticResponse activityStatic(ActivityStaticRequest request) {
        // 收益统计
        AwardStaticRequest awardStaticRequest = awardStaticConvert.activityUserStaticRequest2AwardStaticRequest(request);
        AwardStaticResponse awardStaticResponse = getAwardStaticResponse(awardStaticRequest);
        ActivityStaticResponse response = new ActivityStaticResponse();
        response.setCommission(awardStaticResponse.getCommission())
                .setEstimateCommission(awardStaticResponse.getEstimateCommission())
                .setTbcCommission(awardStaticResponse.getTbcCommission());

        // 活动参与用户统计
        ActivityUserStaticRequest userStaticRequest = awardStaticConvert.activityUserStaticRequest2ActivityUserStaticRequest(request);
        ActivityUserStaticResponse activityUserStaticResponse = activityUserStatic(userStaticRequest);
        response.setUserCount(activityUserStaticResponse.getUserCount())
                .setLimitLeft(activityUserStaticResponse.getLimitLeft())
                .setContributingCount(activityUserStaticResponse.getContributingCount());

        // 已完成用户数量统计
        TaskRecordRequest taskRecordRequest = awardStaticConvert.activityUserStaticRequest2TaskRecordRequest(request);

        // 处理版本兼容问题
        InviteGiftVersionEnum inviteGiftVersion;
        Boolean oldInviteData = request.getOldInviteData();
        if (oldInviteData != null) {
            inviteGiftVersion = activityCommonUtilService.getInviteGiftVersion(oldInviteData, request.getStartTime(), request.getEndTime());
            taskRecordRequest.setInviteGiftVersion(inviteGiftVersion);
            taskRecordRequest.setQueryCurrentTaskStartTime(true);
        }

        long finishUserCount = getActivityFinishUserCount(taskRecordRequest);
        response.setFinishUserCount((int) finishUserCount);
        return response;
    }

    /**
     * 本月剩余席位
     *
     * @return
     */
    private int getLimitLeft(Boolean oldInviteData, TaskRecordRequest staticRequest) {
        String uid = staticRequest.getUid();
        String monthStr;
        //查询个人邀请限额
        if (oldInviteData == null) {
            //0621前未传时间参数查询当月限额
            monthStr = YearMonth.now().format(DateTimeFormatter.ofPattern(TimeUtils.YYYYMM));
        } else if (oldInviteData) {
            //老数据无限额
            return 0;
        } else {
            Date startTime = Optional.ofNullable(staticRequest.getStartTime())
                    .map(DateUtil::date).orElseGet(DateTime::new);
            monthStr = YearMonth.from(startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
                    .format(DateTimeFormatter.ofPattern(TimeUtils.YYYYMM));
        }

        InviteLimitDTO inviteLimitDTO = activityCommonService.queryUserInviteLimit(uid, monthStr);

        //当月已占用限额数
        long currentContributingCount = queryContributedUserCount(uid, monthStr);

        Integer limit = Optional.ofNullable(inviteLimitDTO).map(InviteLimitDTO::getInviteLimit).orElse(0);
        long left = limit - currentContributingCount;
        return Math.toIntExact(left > 0 ? left : 0);
    }

    private long getUserCount(TaskRecordRequest staticRequest) {
        String uid = staticRequest.getUid();
        BoolQueryBuilder commonQuery = getCommonQuery(staticRequest);
        return esCountDistinctPrecise(commonQuery, TIrisUserTaskRecordExample.UID,
                uid, esConfig.getMaxPreciseCount());
    }

    /**
     * 可贡献
     *
     * @param staticRequest
     * @return
     */
    private long getContributingCount(TaskRecordRequest staticRequest) {
        String uid = staticRequest.getUid();
        BoolQueryBuilder commonQuery = getCommonQuery(staticRequest);
        commonQuery.must(QueryBuilders.termQuery("isParticipated", IsParticipatedEnum.YES.name()));
        List<ActivityIdEnum> activityIds = staticRequest.getActivityIds();
        // 邀请有礼需增加任务id过滤
        if (CollectionUtil.isNotEmpty(activityIds)) {
            ActivityIdEnum activityIdEnum = activityIds.get(0);
            if (ActivityIdEnum.INVITE_GIFT.equals(activityIdEnum)) {
                commonQuery.must(QueryBuilders.termQuery("taskId", ActivityTaskIdEnum.INVITE_GMV_TASK.getCode()));
            }
        }
        return esCountDistinctPrecise(commonQuery, TIrisUserTaskRecordExample.UID, uid, esConfig.getMaxPreciseCount());
    }

    /**
     * 获取已完成
     *
     * @param staticRequest staticRequest
     * @return
     */
    private long getActivityFinishUserCount(TaskRecordRequest staticRequest) {
        String uid = staticRequest.getUid();
        BoolQueryBuilder commonQuery = getCommonQuery(staticRequest);
        commonQuery.must(QueryBuilders.termQuery("isParticipated", IsParticipatedEnum.YES.name()));
        commonQuery.must(QueryBuilders.termQuery("awardIssueStatus", TaskRecordAwardIssueStatusEnum.ISSUE_SUCCEED.getCode()));
        return esCountDistinctPrecise(commonQuery, TIrisUserTaskRecordExample.UID, uid, esConfig.getMaxPreciseCount());
    }

    private void handleVersion(ActivityUserStaticResponse response, TaskRecordRequest staticRequest,
                               InviteGiftVersionEnum inviteGiftVersion) {
        String uid = staticRequest.getUid();
        if (inviteGiftVersion == null) {
            return;
        }

        if (Objects.equals(inviteGiftVersion, InviteGiftVersionEnum.V0621)) {
            //0706后 贡献中 = 本月邀请成为下级的用户中，处于上限内的，且未完成的
            BoolQueryBuilder commonQuery = getCommonQuery(staticRequest);
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("currentTaskStartTime");
            Long startTime = inviteGiftVersion.getStartTime();
            Long endTime = inviteGiftVersion.getEndTime();
            if (startTime != null) {
                rangeQuery.gte(startTime);
            }
            if (endTime != null) {
                rangeQuery.lte(endTime);
            }
            commonQuery.must(rangeQuery);
            commonQuery.must(QueryBuilders.termQuery("isParticipated", IsParticipatedEnum.YES.name()));
            commonQuery.must(QueryBuilders.termQuery("taskId", ActivityTaskIdEnum.INVITE_GMV_TASK.getCode()));
            commonQuery.must(QueryBuilders.termQuery("userTaskStatus", UserTaskStatusEnum.PROGRESS.getCode()));
            long contributeUserCount = esCountDistinctPrecise(commonQuery, TIrisUserTaskRecordExample.UID,
                    uid, esConfig.getMaxPreciseCount());
            response.setContributeUserCount(Math.toIntExact(contributeUserCount));
        }
    }

    @Override
    public int deleteInProgressTaskRecord(String uid, String actBizId, String taskBizId) {
        if (Strings.isNullOrEmpty(uid)) {
            throw new TRetailBizException("uid不能为空");
        }
        if (Strings.isNullOrEmpty(actBizId)) {
            throw new TRetailBizException("actBizId不能为空");
        }
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        Criteria criteria = example.createCriteria();
        criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.doSharding(uid))
                .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, actBizId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.USER_TASK_STATUS, UserTaskStatusEnum.PROGRESS.getCode());
        if (!Strings.isNullOrEmpty(taskBizId)) {
            criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.TASK_ID, taskBizId);
        }
        TIrisUserTaskRecordDO record = new TIrisUserTaskRecordDO();
        record.setStatus(UserTaskRecordStatusEnum.DELETED.getCode());
        int i = userTaskRecordMapper.updateByExampleSelective(record, example);
        log.info("deleteRecord 成功删除用户进行中的任务进度{}条，uid:{},actBizId:{},taskBizId:{}", i, uid, actBizId, taskBizId);
        return i;
    }

    @Override
    public List<String> updateTaskRecordPid(int pageSize) {
        List<CompletableFuture<List<String>>> futures = Lists.newArrayList();
        AtomicInteger successNum = new AtomicInteger(0);
        AtomicInteger total = new AtomicInteger(0);
        for (int i = 0; i < ShardingIdUtil.SHARDING_NUM; i++) {
            final int shardingId = i;
            CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(
                    () -> doUpdateTaskRecordPid(pageSize, shardingId, total, successNum), irisFreshDataThreadExecutor);
            futures.add(future);
        }

        try {
            List<String> res = ConcurrentUtils.allOf(futures);
            log.info("更新pid成功，总共更新成功{}个任务记录，未查询到pid的任务记录id：{}", successNum.get(), JSON.toJSONString(res));
            return res;
        } catch (Exception e) {
            log.error("更新pid结束，未能正常执行所有更新线程，总共更新成功{}个任务记录：", successNum.get(), e);
        }
        return Collections.emptyList();
    }

    private List<String> doUpdateTaskRecordPid(int pageSize, int shardingId, AtomicInteger total,
                                               AtomicInteger successNum) {
        List<String> notPidRecordId = Lists.newArrayList();
        int pageNum = 1;
        List<TIrisUserTaskRecordDO> records = queryNoPidTaskRecord(shardingId, pageNum, pageSize, null);
        DependencyConfig.Config freshData = dependencyConfig.getConfigs().get("freshData");
        while (CollectionUtil.isNotEmpty(records)) {
            try {
                if (activityConfig.isStopFreshPid()) {
                    log.info("刷pid因停止配置更新结束，shardingId：{}，当前所有更新成功uid数：{}，查询不到pid的记录id：{}", shardingId,
                            successNum.get(), notPidRecordId);
                    return notPidRecordId;
                }

                for (TIrisUserTaskRecordDO record : records) {
                    total.incrementAndGet();
                    if (freshData != null) {
                        FRESH_DATA_RATELIMITER.setRate(freshData.getPermitsPerSecond());
                        FRESH_DATA_RATELIMITER.acquire();
                        log.info("刷pid，当前限流{}qps", FRESH_DATA_RATELIMITER.getRate());
                    }
                    String uid = record.getUid();
                    SupervisorRelationResponse response = userCoreDependency.queryUserSupervisor(uid);
                    String pid = Optional.ofNullable(response)
                            .map(SupervisorRelationResponse::getParentUid).orElse(null);
                    if (StrUtil.isBlank(pid)) {
                        notPidRecordId.add(record.getBizId());
                        continue;
                    }
                    TIrisUserTaskRecordDO update = new TIrisUserTaskRecordDO();
                    update.setPid(pid);
                    update.setUpdateTime(new Date());
                    TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
                    example.createCriteria()
                            .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, shardingId)
                            .andPropertyEqualTo(TIrisUserTaskRecordExample.BIZ_ID, record.getBizId());
                    userTaskRecordMapper.updateByExampleSelective(update, example);
                    successNum.incrementAndGet();
                }

                Long maxId = records.stream().map(TIrisUserTaskRecordDO::getId).max(Long::compareTo).orElse(null);
                records = queryNoPidTaskRecord(shardingId, ++pageNum, pageSize, maxId);
            } catch (Exception e) {
                log.error("刷pid失败，shardingId：{}，当前所有更新成功uid数：{}，查询不到pid的记录id：{}", shardingId, successNum.get(),
                        notPidRecordId);
            }
        }

        log.info("更新pid完成，shardingId：{}，总处理数：{}，总更新成功数：{}，查询不到pid的记录id：{}", shardingId, total.get(), successNum.get(),
                notPidRecordId);
        return notPidRecordId;
    }

    private List<TIrisUserTaskRecordDO> queryNoPidTaskRecord(int shardingId, int pageNum, int pageSize,
                                                             Long searchAfter) {
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.setOrderByClause("id asc");
        Criteria criteria = example.createCriteria();
        criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, shardingId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.STATUS, EYesNo.NO.getValue())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.PID, StrUtil.EMPTY);

        if (searchAfter != null) {
            criteria.andPropertyGreaterThan(TIrisUserTaskRecordExample.ID, searchAfter);
        }

        List<TIrisUserTaskRecordDO> recordDOS = userTaskRecordMapper.limitSelectByExample(example, 0, pageSize);
        log.info("查询刷pid任务数据，共查询{}条", recordDOS.size());
        return recordDOS;
    }

    @Override
    public boolean updateTaskRecordGmv(int pageSize, Integer shardingId) {
        AtomicInteger successNum = new AtomicInteger(0);
        AtomicInteger total = new AtomicInteger(0);
        if (shardingId != null) {
            return doUpdateTaskRecordGmv(pageSize, shardingId, total, successNum);
        } else {
            List<CompletableFuture<Boolean>> futures = Lists.newArrayList();
            for (int i = 0; i < ShardingIdUtil.SHARDING_NUM; i++) {
                final int shard = i;
                CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(
                        () -> doUpdateTaskRecordGmv(pageSize, shard, total, successNum), irisFreshDataThreadExecutor);
                futures.add(future);
            }

            try {
                boolean allSuccess = ConcurrentUtils.allOf(i -> i, futures);
                if (!allSuccess) {
                    log.error("更新gmv结束，未能正常执行所有更新线程，总共更新成功{}个任务记录：", successNum.get());
                }
                return allSuccess;
            } catch (Exception e) {
                log.error("更新gmv结束，未能正常执行所有更新线程，总共更新成功{}个任务记录：", successNum.get(), e);
            }
        }

        return false;
    }

    @Override
    public Pair<Integer/**邀请总人数**/, Integer/**可以贡献的人数**/> queryInviteLimitSeqByPid(String pid, Date date) {
        Integer inviteTotal;
        Integer inviteLimitNum;
        String inviteLimitCacheKey = String.format(ActivityConfigConstants.INVITE_LIMIT_CACHE_UID_MONTH_KEY, pid,
                DateUtil.format(date, "yyyyMM"));
        String s = redisClient.get(inviteLimitCacheKey);
        if (StringUtils.isNotBlank(s)) {
            String[] split = s.split(",");
            log.info("queryInviteLimitSeqByPid redis ,pid:{},value:{}", pid, s);
            return Pair.of(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
        }
        //查询uid已使用邀请限额
        DateTime begin = DateUtil.beginOfMonth(date);
        DateTime end = DateUtil.endOfMonth(date);
        ActivityUserStaticRequest countReq = new ActivityUserStaticRequest();
        countReq.setActivityTypes(Arrays.asList(ActivityTypeEnum.INVITE_GIFT));
        countReq.setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT));
        countReq.setTaskIds(Arrays.asList(ActivityTaskIdEnum.INVITE_GMV_TASK));
        countReq.setUid(pid);
        countReq.setStartTime(begin.getTime());
        countReq.setEndTime(end.getTime());
        countReq.setQueryCurrentTaskStartTime(true);
        inviteTotal = Math.toIntExact(countDistinctUid(countReq));
        countReq.setParticipated(IsParticipatedEnum.YES);
        inviteLimitNum = Math.toIntExact(countDistinctUid(countReq));
        log.info("queryInviteLimitSeqByPid pid:{},date:{},inviteTotal:{},inviteLimitNum:{}", pid, date, inviteTotal,
                inviteLimitNum);
        StringBuilder value = new StringBuilder().append(inviteTotal).append(",").append(inviteLimitNum);
        redisClient.setex(inviteLimitCacheKey, value.toString(), 3600 * 24 * 40);
        return Pair.of(inviteTotal, inviteLimitNum);
    }

    @Override
    public void deleteInviteLimitCache(String pid, String uid) {
        log.info("deleteInviteLimitCache pid:{},uid:{}", pid, uid);
        if (StringUtils.isBlank(pid) || StringUtils.isBlank(uid)) {
            return;
        }
        Long becomeTraineeTime = activityCommonService.queryTraineeTime(uid);
        log.info("deleteInviteLimitCache pid:{},uid:{},becomeTraineeTime:{}", pid, uid, becomeTraineeTime);
        if (Objects.isNull(becomeTraineeTime)) {
            return;
        }
        String inviteLimitCacheKey = String.format(ActivityConfigConstants.INVITE_LIMIT_CACHE_UID_MONTH_KEY, pid,
                DateUtil.format(new Date(becomeTraineeTime), "yyyyMM"));

        String inviteAwardLimitCacheKey = String.format(ActivityConfigConstants.IRIS_INVITE_UPPER_RECORD_AWARD_LIMIT_CACHE_KEY, pid,
                DateUtil.format(new Date(becomeTraineeTime), "yyyyMM"));

        redisClient.del(inviteLimitCacheKey, inviteAwardLimitCacheKey);
    }

    @Override
    public void incrInviteLimitCache(String pid, String uid, String isParticipated) {
        log.info("incrInviteLimitCache pid:{},uid:{},isParticipated:{}", pid, uid, isParticipated);
        if (StringUtils.isBlank(pid) || StringUtils.isBlank(uid)) {
            return;
        }
        Long becomeTraineeTime = activityCommonService.queryTraineeTime(uid);
        log.info("incrInviteLimitCache pid:{},uid:{},becomeTraineeTime:{}", pid, uid, becomeTraineeTime);
        if (Objects.isNull(becomeTraineeTime)) {
            return;
        }
        String inviteLimitCacheKey = String.format(ActivityConfigConstants.INVITE_LIMIT_CACHE_UID_MONTH_KEY, pid,
                DateUtil.format(new Date(becomeTraineeTime), "yyyyMM"));
        String s = redisClient.get(inviteLimitCacheKey);
        if (StringUtils.isNotBlank(s)) {
            log.info("incrInviteLimitCache cache value:{}", s);
            String[] split = s.split(",");
            Integer inviteTotal = Integer.parseInt(split[0]) + 1;
            Integer inviteLimitNum = Integer.parseInt(split[1]);
            if (isParticipated.equals(TaskBatchDateIsParticipatedEnum.YES.getCode())) {
                inviteLimitNum = inviteLimitNum + 1;
            }
            StringBuilder value = new StringBuilder().append(inviteTotal).append(",").append(inviteLimitNum);
            redisClient.setex(inviteLimitCacheKey, value.toString(), 3600 * 24 * 40);
        }

    }

    private Boolean doUpdateTaskRecordGmv(int pageSize, int shardingId, AtomicInteger total, AtomicInteger successNum) {
        List<String> notGmvRecordId = Lists.newArrayList();
        List<TIrisUserTaskRecordDO> records = queryAllTaskRecord(shardingId, pageSize, null);
        DependencyConfig.Config freshData = dependencyConfig.getConfigs().get("freshData");
        while (CollectionUtil.isNotEmpty(records)) {
            if (activityConfig.isStopFreshGmv()) {
                log.info("刷gmv因停止配置更新结束，shardingId：{}，当前所有更新成功uid数：{}，查询不到gmv的记录id：{}", shardingId, successNum.get(),
                        notGmvRecordId);
                return true;
            }

            for (TIrisUserTaskRecordDO record : records) {
                try {
                    total.incrementAndGet();
                    if (freshData != null) {
                        FRESH_DATA_RATELIMITER.setRate(freshData.getPermitsPerSecond());
                        FRESH_DATA_RATELIMITER.acquire();
                        log.info("刷gmv，当前限流{}qps", FRESH_DATA_RATELIMITER.getRate());
                    }
                    String uid = record.getUid();
                    String startTime = TimeUtils.parse(record.getCurrentTaskStartTime(), TimeUtils.YYYY_MM_DD);
                    String endTime = TimeUtils.parse(record.getCurrentTaskEndTime(), TimeUtils.YYYY_MM_DD);
                    PersonalPerformanceReq.PersonalPerformanceDto personalPerformanceDto = PersonalPerformanceReq.PersonalPerformanceDto
                            .builder().uid(uid)
                            .salesDateBegin(startTime).salesDateEnd(endTime).build();
                    PersonalPerformanceReq req = PersonalPerformanceReq.builder()
                            .data(personalPerformanceDto).pageNo(1).pageSize(1).build();
                    PaginationResponse<QuFaPerformancePersonalRes> response = groupTaskDependency
                            .personalPerformanceList(req);
                    if (response == null || CollectionUtil.isEmpty(response.getDataList())
                            || response.getDataList().get(0).getSalesAmt() == null
                            || response.getDataList().get(0).getSalesAmt() == 0) {
                        notGmvRecordId.add(record.getBizId());
                        continue;
                    }

                    Long salesAmt = response.getDataList().get(0).getSalesAmt();
                    TIrisUserTaskRecordDO update = new TIrisUserTaskRecordDO();
                    update.setGmv(Math.toIntExact(salesAmt));
                    TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
                    example.createCriteria()
                            .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, shardingId)
                            .andPropertyEqualTo(TIrisUserTaskRecordExample.BIZ_ID, record.getBizId());
                    userTaskRecordMapper.updateByExampleSelective(update, example);
                    successNum.incrementAndGet();
                } catch (Exception e) {
                    log.error("刷新gmv错误，shardingId：{}，总处理数：{}，总更新成功数：{}，查询不到gmv的记录id：{}", shardingId, total.get(),
                            successNum.get(), notGmvRecordId, e);
                }
            }
            Long maxId = records.stream().map(TIrisUserTaskRecordDO::getId).max(Long::compareTo).orElse(null);
            records = queryAllTaskRecord(shardingId, pageSize, maxId);
        }

        log.info("更新gmv完成，shardingId：{}，总处理数：{}，总更新成功数：{}，查询不到gmv的记录id：{}", shardingId, total.get(), successNum.get(),
                notGmvRecordId);
        return true;
    }

    private List<TIrisUserTaskRecordDO> queryAllTaskRecord(int shardingId, int pageSize, Long searchAfter) {
        TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
        example.setOrderByClause(TIrisUserTaskRecordExample.ID + " asc");

        Criteria criteria = example.createCriteria();
        criteria.andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, shardingId)
                .andPropertyEqualTo(TIrisUserTaskRecordExample.STATUS, EYesNo.NO.getValue())
                .andPropertyEqualTo(TIrisUserTaskRecordExample.GMV, 0)
                .andPropertyIn(TIrisUserTaskRecordExample.ACTIVITY_TYPE,
                        Arrays.asList(ActivityTypeEnum.MONTH_GIFT.getCode(), ActivityTypeEnum.INVITE_GIFT.getCode()));

        if (searchAfter != null) {
            criteria.andPropertyGreaterThan(TIrisUserTaskRecordExample.ID, searchAfter);
        }

        List<TIrisUserTaskRecordDO> recordDOS = userTaskRecordMapper.limitSelectByExample(example, 0, pageSize);
        log.info("查询刷gvm任务数据，共查询{}条数据", recordDOS.size());
        return recordDOS;
    }

    @Override
    public List<String> queryInviteTaskRecordByPid(String pid, Date month, List<Byte> statusList) {
        List<TIrisUserTaskRecordDO> records = queryUserTaskRecordDOSByPidEs(
                pid, month, statusList);

        return records.stream().map(TIrisUserTaskRecordDO::getUid).collect(Collectors.toList());
    }

    @Override
    public List<TIrisUserTaskRecordDO> queryUserTaskRecordDOSByPidEs(String pid, Date month, List<Byte> statusList) {
        DateTime begin = DateUtil.beginOfMonth(month);
        DateTime end = DateUtil.endOfMonth(month);

        TaskRecordRequest request = new TaskRecordRequest()
                .setUid(pid).setStartTime(begin.getTime())
                .setEndTime(end.getTime()).setUserTaskStatus(statusList)
                .setActivityIds(Arrays.asList(ActivityIdEnum.INVITE_GIFT))
                .setTaskIds(Arrays.asList(ActivityTaskIdEnum.INVITE_GMV_TASK));
        BoolQueryBuilder commonQuery = getCommonQuery(request);
        EsQueryDTO esQueryDTO = EsQueryDTO.builder().query(commonQuery).routing(pid)
                .pageNum(1).pageSize(esConfig.getMaxPageSize()).build();

        Function<SearchResponse, List<TIrisUserTaskRecordDO>> func = (r) -> ESUtils.buildResponse(r, TIrisUserTaskRecordDO.class);
        List<TIrisUserTaskRecordDO> records = searchList(esQueryDTO, func);
        return records;
    }

    /**
     * pid调整发奖上限，处理pid下级的限额情况
     *
     * @param request
     */
    @Override
    public HttpResult<String> processUpdateLimit(ProcessUpdateLimitRequest request) {

        String uid = request.getUid();
        String month = request.getMonth();
        try {
            Date monthDate = DateUtil.parse(month, "yyyyMM");
            //查询pid发奖上限和已发奖数量
            InviteLimitDTO inviteLimitDTOByAward = activityCommonService.queryInviteLimitByAward(uid, monthDate.getTime());
            if (inviteLimitDTOByAward.isError()) {
                log.error("查询邀请上限失败，uid：{}，inviteLimitDTO：{}", uid, JSON.toJSONString(inviteLimitDTOByAward));
                throw new TRetailErrorException(inviteLimitDTOByAward.getDesc() + "，查询邀请上限失败");
            }
            //邀请上限
            Integer inviteLimit = inviteLimitDTOByAward.getInviteLimit();
            //已贡献的人数
            Integer inviteDevoteNum = inviteLimitDTOByAward.getInviteDevoteNum();
            if (inviteLimit <= inviteDevoteNum) {
                log.info("修改邀请上限，以贡献人数超过邀请上限，不再调整受限情况 uid:{},month:{},inviteLimit:{},inviteDevoteNum:{}", uid, month,
                        inviteLimit, inviteDevoteNum);
                return HttpResult.succ(String.format("修改邀请上限，以贡献人数超过邀请上限，不再调整受限情况 uid:%s,month:%s,inviteLimit:%s,inviteDevoteNum:%s", uid, month,
                        inviteLimit, inviteDevoteNum));
            }
            //剩余限额
            log.info("processUpdateLimit inviteLimitDTOByAward:{}", JSON.toJSONString(inviteLimitDTOByAward));
            int residualLimit = inviteLimit - inviteDevoteNum;

            List<TIrisUserTaskRecordDO> recordDOS = queryUserTaskRecordDOSByPidEs(uid, monthDate,
                    Arrays.asList(UserTaskStatusEnum.PROGRESS.getCode(),
                            UserTaskStatusEnum.LIMITED.getCode(), UserTaskStatusEnum.FINISHED.getCode()));
            if (CollectionUtil.isEmpty(recordDOS)) {
                log.info("调整pid发奖上限，pid当月下级进行中的任务记录为空，uid:{} month:{}", uid, month);
                return HttpResult.succ(String.format("调整pid发奖上限，pid当月下级进行中的任务记录为空 uid:%s,month:%s,inviteLimit:%s,inviteDevoteNum:%s", uid, month,
                        inviteLimit, inviteDevoteNum));
            }

            //更新所有受限记录为不受限
            List<TIrisUserTaskRecordDO> limitedList = recordDOS.stream()
                    .filter(n -> IsParticipatedEnum.LIMITED.name().equals(n.getIsParticipated()))
                    .collect(Collectors.toList());
            if (CollectionUtil.isEmpty(limitedList)) {
                log.info("调整用户发奖上限，用户当月下级无受限记录，uid:{} month:{}", uid, month);
                return HttpResult.succ(String.format("调整pid发奖上限，pid当月下级无受限记录 uid:%s,month:%s,inviteLimit:%s,inviteDevoteNum:%s", uid, month,
                        inviteLimit, inviteDevoteNum));
            }
            List<String> limitedAllUids = limitedList.stream().map(n -> n.getUid()).collect(Collectors.toList());

            //过滤出受限，且已完成的记录
            List<TIrisUserTaskRecordDO> recordListNeedRetry = recordDOS.stream()
                    .filter(n -> IsParticipatedEnum.LIMITED.name().equals(n.getIsParticipated()))
                    .filter(n -> UserTaskStatusEnum.FINISHED.getCode() == n.getUserTaskStatus())
                    .sorted((o1, o2) -> {
                        if (o1.getOrderFinishTime() != null && o2.getOrderFinishTime() != null) {
                            return o1.getOrderFinishTime().compareTo(o2.getOrderFinishTime());
                        } else if (o1.getOrderFinishTime() != null || o2.getOrderFinishTime() == null) {
                            return 1;
                        } else if (o1.getOrderFinishTime() == null || o2.getOrderFinishTime() != null) {
                            return -1;
                        }
                        return 0;
                    }).collect(Collectors.toList());

            //更新需要解封的任务进度，并更新为进行中
            updateUserTaskRecordIsParticipated(limitedAllUids, TaskBatchDateIsParticipatedEnum.YES, UserTaskStatusEnum.PROGRESS);

            recordListNeedRetry.forEach(record -> {
                //重试发奖
                EventRetryRequest req = EventRetryRequest.builder()
                        .eventType(ActivityEventTypeEnum.DISTRIBUTION_ORDER.getCode())
                        .uidList(Arrays.asList(record.getUid()))
                        .activityId("INVITE_GIFT")
                        .taskId("INVITE_GMV_TASK")
                        .startTime(DateUtil.format(record.getCurrentTaskStartTime(), "yyyy-MM-dd HH:mm:ss"))
                        .endTime(DateUtil.format(record.getCurrentTaskEndTime(), "yyyy-MM-dd HH:mm:ss"))
                        .eventInfo("%orderStatus\\\\\":\\\\\"SUCCESS%")
                        .build();
                List<TIrisEventHandingRecordDO> handingRecordDOList = irisEventHandingRecordService.queryHandingRecords(
                        ShardingIdUtil.doSharding(record.getUid()), 0, 1, req);
                if (CollectionUtil.isNotEmpty(handingRecordDOList)) {
                    activityTaskEventRetryJob.doRetry(handingRecordDOList.get(0));
                }

            });
        } catch (Exception e) {
            log.error("修改邀请上限处理异常, uid:{},month:{},error:{}", uid, month, e.getMessage(), e);
            return HttpResult.fail(String.format("处理失败,uid:%s,month:%s,error:%s", uid, month, e.getMessage()));
        }
        return HttpResult.succ("执行成功");

    }

    @Resource
    private ActivityTaskEventRetryJob activityTaskEventRetryJob;

    @Override
    public void updateUserTaskRecordIsParticipated(List<String> uidList,
                                                   TaskBatchDateIsParticipatedEnum isParticipated,
                                                   UserTaskStatusEnum userTaskStatusEnum) {
        if (CollectionUtils.isEmpty(uidList)) {
            return;
        }
        log.info("updateUserTaskRecordIsParticipated uidList:{},isParticipated:{}", uidList, isParticipated.getCode());
        AtomicInteger successNum = new AtomicInteger(0);
        List<CompletableFuture<Boolean>> futures = Lists.newArrayList();
        List<String> successUidList = new ArrayList<>();
        for (int i = 0; i < uidList.size(); i++) {
            String uid = uidList.get(i);
            CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(
                    () -> doUpdateTaskRecordIsParticipated(uid, successNum, successUidList, isParticipated, userTaskStatusEnum), irisFreshDataThreadExecutor);
            futures.add(future);
        }
        try {
            boolean allSuccess = ConcurrentUtils.allOf(i -> i, futures);
            if (!allSuccess) {
                uidList.removeAll(successUidList);
                log.error("更新邀请有礼受限状态结束，未能正常执行所有更新线程，任务总数:{},总共更新成功{}个任务记录："
                        , uidList.size(), successNum.get());
                log.info("更新邀请有礼受限状态结束，未能正常执行所有更新线程,失败uid:{}", uidList);
            }
        } catch (Exception e) {
            log.error("更新邀请有礼受限状态结束，未能正常执行所有更新线程，任务总数:{},总共更新成功{}个任务记录：",
                    uidList.size(), successNum.get(), e);
            log.info("更新邀请有礼受限状态结束，未能正常执行所有更新线程,失败uid:{}", uidList);
        }

    }

    private Boolean doUpdateTaskRecordIsParticipated(String uid, AtomicInteger successNum, List<String> successUidList,
                                                     TaskBatchDateIsParticipatedEnum isParticipated, UserTaskStatusEnum userTaskStatusEnum) {
        try {
            TIrisUserTaskRecordDO update = new TIrisUserTaskRecordDO();
            update.setIsParticipated(isParticipated.getCode());
            update.setUpdateTime(new Date());
            if (userTaskStatusEnum != null) {
                update.setUserTaskStatus(userTaskStatusEnum.getCode());
            }
            TIrisUserTaskRecordExample example = new TIrisUserTaskRecordExample();
            example.createCriteria()
                    .andPropertyEqualTo(TIrisUserTaskRecordExample.SHARDING_ID, ShardingIdUtil.sharding(uid))
                    .andPropertyEqualTo(TIrisUserTaskRecordExample.UID, uid)
                    .andPropertyEqualTo(TIrisUserTaskRecordExample.ACTIVITY_ID, activityConfig.getInviteGiftActivityId())
                    .andPropertyIn(TIrisUserTaskRecordExample.AWARD_ISSUE_STATUS,
                            Arrays.asList(TaskRecordAwardIssueStatusEnum.UNISSUED.getCode()
                                    , TaskRecordAwardIssueStatusEnum.ISSUE_UNABLE.getCode()));
            int num = userTaskRecordMapper.updateByExampleSelective(update, example);
            log.info("doUpdateTaskRecordIsParticipated update uid:{},update:{},num:{}"
                    , uid, JSON.toJSONString(update), num);
            successUidList.add(uid);
            successNum.incrementAndGet();
        } catch (Exception e) {
            log.error("更新邀请有礼受限状态错误，uid：{},msg:{}", uid, e.getMessage(), e);
            return false;
        }
        return true;
    }

    @Override
    public FlowActivityInfoResponse queryFlowActivityInfo(FlowActivityInfoRequest request) {
        FlowActivityInfoRequest.LevelUpReq levelUpReq = request.getLevelUpReq();
        if (levelUpReq != null) {
            //查询晋升有礼信息
            return getLevelUpInfo(request.getUid(), levelUpReq);
        }

        Long taskRecordId = request.getTaskRecordId();
        String uid = request.getUid();
        BoolQueryBuilder query = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.PID, uid))
                .must(QueryBuilders.termQuery(TIrisUserTaskRecordExample.STATUS, UserTaskRecordStatusEnum.NORMAL.getCode()))
                .must(QueryBuilders.termQuery(StrUtil.toCamelCase(TIrisUserTaskRecordExample.BIZ_ID), taskRecordId));
        Function<SearchResponse, List<TIrisUserTaskRecordDO>> func = (r) -> ESUtils.buildResponse(r, TIrisUserTaskRecordDO.class);
        EsQueryDTO esQueryDTO = EsQueryDTO.builder().routing(uid).query(query).pageNum(1).pageSize(1).build();
        List<TIrisUserTaskRecordDO> records = searchList(esQueryDTO, func);
        if (CollectionUtil.isEmpty(records)) {
            return null;
        }
        return new FlowActivityInfoResponse().setUid(records.get(0).getUid());
    }

    /**
     * 查询晋升有礼信息
     *
     * @param levelUpReq
     * @return
     */
    private FlowActivityInfoResponse getLevelUpInfo(String uid, FlowActivityInfoRequest.LevelUpReq levelUpReq) {
        String taskBizId = levelUpReq.getTaskId();
        //查询升级事件
        TIrisEventHandingRecordDO eventHandingRecord = irisEventHandingRecordService.queryOneHandingRecord(ShardingIdUtil.doSharding(uid), null, uid, taskBizId);
        if (eventHandingRecord == null) {
            return null;
        }

        String eventInfoStr = eventHandingRecord.getEventInfo();
        JSONObject jsonObject = JSON.parseObject(eventInfoStr);
        if (jsonObject == null) {
            return null;
        }

        JSONObject eventInfo = Optional.ofNullable(jsonObject.getJSONObject("eventInfo")).orElseGet(JSONObject::new);
        String afterLevelId = eventInfo.getString("afterLevelId");
        Long levelUpTime = eventInfo.getLong("timeStamp");

        FlowActivityInfoResponse response = new FlowActivityInfoResponse()
                .setUid(uid).setLevel(afterLevelId).setLevelUpTime(levelUpTime);
        return response;
    }

    /**
     * 活动记录表已排序，根据活动记录表排序后的数据返回任务记录
     *
     * @param userTaskRecordList 任务记录
     * @param userActivityList   活动记录
     * @return 排好序的任务记录
     */
    private List<UserTaskRecordResponse> sortUserTaskRecordResponse(List<UserTaskRecordResponse> userTaskRecordList,
                                                                    List<TIrisUserActivityRecordDO> userActivityList) {
        Map<String, List<UserTaskRecordResponse>> userTaskRecordResponseMap = userTaskRecordList.stream()
                .collect(Collectors.groupingBy(UserTaskRecordResponse::getActivityRecordId));
        List<UserTaskRecordResponse> userTaskRecordSortedList = new ArrayList<>(userTaskRecordList.size());
        userActivityList.forEach(userActivity -> {
            List<UserTaskRecordResponse> userTaskRecordResponseList = userTaskRecordResponseMap.get(userActivity.getBizId());
            if (CollectionUtil.isNotEmpty(userTaskRecordResponseList)) {
                // 设置被邀请时间
                userTaskRecordResponseList.forEach(userTaskRecordResponse -> {
                    Date inviteTime = userActivity.getInviteTime();
                    if (Objects.nonNull(inviteTime)) {
                        userTaskRecordResponse.setInviteTime(inviteTime.getTime());
                    }
                });
                if (CollectionUtil.isNotEmpty(userTaskRecordResponseList)) {
                    userTaskRecordSortedList.addAll(userTaskRecordResponseList);
                }
            } else {
                log.error("通过活动记录bizId({})未获取到任务记录列表", userActivity.getBizId());
            }
        });

        return userTaskRecordSortedList;
    }

    /**
     * 组装返回结果
     *
     * @param userTaskRecordSortedList userTaskRecordSortedList
     */
    private void assembleRsp(List<UserTaskRecordResponse> userTaskRecordSortedList) {
        List<String> taskIds = userTaskRecordSortedList.stream()
                .map(UserTaskRecordResponse::getTaskId).collect(Collectors.toList());
        List<TIrisActivityTaskDO> tasks = irisActivityTaskService.getTasksByIds(taskIds);
        Map<String, TIrisActivityTaskDO> taskMap = tasks.stream()
                .collect(Collectors.toMap(i -> String.valueOf(i.getBizId()), i -> i, (i1, i2) -> i1));

        Map<String, MultiTaskActivityDTO> multiTaskActivityConfig = activityConfig.getMultiTaskActivityConfig();
        for (UserTaskRecordResponse response : userTaskRecordSortedList) {

            String uid = response.getUid();

            String taskId = response.getTaskId();
            TIrisActivityTaskDO taskDO = Optional.ofNullable(taskMap.get(taskId))
                    .orElseGet(TIrisActivityTaskDO::new);

            MultiTaskActivityDTO multiTaskActivityDTO = multiTaskActivityConfig.get(response.getActivityId());
            String groupByExpression = Optional.ofNullable(multiTaskActivityDTO)
                    .map(MultiTaskActivityDTO::getGroupByExpression).orElse(null);

            //门槛，测试用户取七彩石配置
            String conditionThreshold = taskDO.getConditionThreshold();
            TargetThresholdVO threshold = Optional.ofNullable(JSON.parseObject(
                    conditionThreshold, TargetThresholdVO.class)).orElseGet(TargetThresholdVO::new);
            //权益信息
            String awardInfo = taskDO.getAwardInfo();
            AwardInfoDTO awardInfoDTO = activityCommonService.getAwardInfoCacheByMarket(awardInfo);

            response.setTotalCommission(threshold.getTargetCommission())
                    .setTotalShareCount(threshold.getTargetShare())
                    .setAwardType(awardInfoDTO.getType())
                    .setAwardValue(Optional.ofNullable((awardInfoDTO.getValue())).orElse(0))
                    .setGroupByExpression(groupByExpression)
                    .setCommissionTaskPlusDay(activityConfig.getCommissionPlusDays(uid))
                    .setSingleTaskInMultiActivity(activityConfig.getSingleTaskInMultiActivity().contains(taskId));
        }
    }
}
